/**
 * 状态看板
 * @Author: Admin
 * @Date: 2021/1/26 16:54
 */
import React, {Component} from "react";
import {cloneDeep, concat, isArray, isEmpty, isFunction, map, uniqBy} from "lodash-es";
import {
    DragDropContext,
    Droppable,
    Draggable,
} from 'react-beautiful-dnd';
import update from 'immutability-helper';
import styles from './index.module.less';
import {SyncOutlined} from '@ant-design/icons';
import {isNotEmpty, isObjectValEqual} from "jh-utils";
import {Spin} from "antd";
import {compValuePreview} from "../Base/helper/compValuePreview";
import {findKanbanConfApi, changeKanbanStateApi} from "../Config/GlobalApi";


let Issue = (props) => {
    const {id, issueIndex, issue, appins, colsConf} = props;
    let math = Math.floor(Math.random() * 9);
    let taskShadow = 'taskShadow-' + (Math.ceil(math) === 0 ? 1 : Math.ceil(math));

    return (
        <Draggable draggableId={`${id}`} index={issueIndex}>
            {(provided, snapshot) => (
                <div
                    onDoubleClick={() => {
                    }}
                    ref={provided.innerRef}
                    className={`${snapshot.isDragging ? styles.issueDragging : styles.issue} ${styles[taskShadow]}`}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                >
                    {
                        !isEmpty(colsConf) && map(colsConf, (item, index) => {
                            if (index < 3) {
                                let value = compValuePreview(item.componentType, {
                                    appins,
                                    value: issue[item.name],
                                    record: issue,
                                    col: item,
                                    dataIndex: item.dataIndex,
                                    selector: item.selector,
                                });
                                return <div className={`${styles.overHidden} ${styles.lineName}`} title={value}>
                                    <span style={{color: '#000'}}>
                                        {
                                            item.remark + ': '
                                        }
                                    </span>
                                    {value}
                                </div>
                            }
                            return ''
                        })
                    }

                </div>
            )}
        </Draggable>
    );
};

/**
 * 看板模块
 */
class Column extends Component {
    constructor(props) {
        super(props);

    }

    /**
     * 加载更多数据
     */
    loadMore(state) {
        const {loadMore} = this.props;
        if (isNotEmpty(state) && isFunction(loadMore)) {
            loadMore(state);
        }
    }

    render() {
        const {columnIndex, activeColumn, column, activeIssues, appins, colsConf} = this.props;
        const {id, issues = []} = column;
        return (
            <div className={styles.column}>
                <div className={styles.columnTitle}>
                    {column.name} ( {issues.length} )
                </div>
                <Droppable
                    droppableId={`${columnIndex}`}
                    isDropDisabled={
                        activeColumn
                            ? !(activeColumn.acceptIds.includes(id) || id === activeColumn.id)
                            : true
                    }
                >
                    {(provided, snapshot) => (
                        <div
                            ref={provided.innerRef}
                            className={
                                snapshot.isDraggingOver
                                    ? styles.columnContentActive
                                    : styles.columnContent
                            }
                            {...provided.droppableProps}
                        >
                            {issues.map((issue, index) => (
                                <Issue
                                    colsConf={colsConf}
                                    appins={appins}
                                    parent={column}
                                    key={issue.id}
                                    issueIndex={index}
                                    id={issue.id}
                                    issue={issue}
                                />
                            ))}
                            {
                                <div style={{display: snapshot.isDraggingOver ? 'none' : ''}}
                                     onClick={e => this.loadMore(id)}
                                     className={styles.addMore}>
                                    <SyncOutlined/> 加载更多...
                                </div>
                            }
                            {provided.placeholder}
                        </div>
                    )}
                </Droppable>
            </div>
        );
    }
}

export default class StatusBoard extends Component {

    constructor(props) {
        super(props);
        this.state = {
            list: [], // 看板数据
            config: [], // 看板初始配置
            colsConf: [], // 字段配置
            loading: false,
            activeColumn: null, // 可拖拽条件约束
            activeIssues: null, //当前拖拽的对象数据
        }
    }

    componentDidMount() {
        const $this = this.props.qtins || {};
        let appCode = $this.getAppCode();
        let {colsConf = []} = $this && $this.props || {};
        this.setState({colsConf});
        this.getStatusConfig(appCode);
    }

    componentDidUpdate(prevProps, prevState) {
        if (!isObjectValEqual(prevProps.initList, this.props.initList) || prevProps.initList !== this.props.initList) {
            // console.log('this.props.initList', this.props.initList);
            let list = this.initListFn(this.props.initList);
            this.setState({list})
        }
    }

    /**
     * 获取应用状态机配置
     * @param appCode
     */
    getStatusConfig(appCode) {
        if (appCode) {
            const $this = this.props.qtins;
            if ($this.request) {
                let ajaxData = {
                    appCode
                };
                let _this = this;
                this.setState({loading: true});
                $this.request(findKanbanConfApi, ajaxData).then(rsp => {
                    if (rsp && 200 == rsp.status && rsp.data) {
                        let config = rsp.data;
                        // console.log('config', config);
                        if (!isEmpty(config)) {
                            const {fetchList} = _this.props;
                            _this.setState({config}, () => {
                                fetchList && fetchList();
                            });
                        }
                    }
                }).finally(() => {
                    _this.setState({loading: false});
                })
            }
        }
    }

    /**
     * 初始化转换看板数据
     * @param list
     */
    initListFn(list = []) {
        let data = [], {config} = this.state, categorizeObj = {};
        if (!isEmpty(config)) {
            map(list, item => {
                if (item && !isEmpty(item.state)) {
                    if (!categorizeObj.hasOwnProperty(item.state.id)) {
                        categorizeObj[item.state.id] = [];
                    }
                    categorizeObj[item.state.id].push(item);
                }
                return item;
            });

            data = map(config, item => {
                item.issues = [];
                if (!isEmpty(categorizeObj) && item && categorizeObj.hasOwnProperty(item.id)) {
                    item.issues = categorizeObj[item.id];
                }
                return item;
            })
        }

        return data;
    }

    /**
     * 更新list,用于分页插入数据
     * @param state
     * @param data
     */
    updatePushListFn(state, data) {
        let {list} = this.state;
        if (isNotEmpty(state) && !isEmpty(data) && !isEmpty(list)) {
            list = map(list, item => {
                if (item.id === state) {
                    if (!isArray(item.issues)) {
                        item.issues = [];
                    }
                    let issues = concat(item.issues, data);
                    item.issues = uniqBy(issues, 'id');
                }
                return item;
            });
            this.setState({list});
        }
    }

    onDragStart(result) {
        const {source} = result;
        const columnIndex = Number(source.droppableId);
        const issueIndex = source.index;
        const {list} = this.state;
        this.setState({
            activeColumn: list[columnIndex],
            activeIssues: list[columnIndex].issues[issueIndex]
        })
    }

    onDragEnd(result) {
        const {destination, source} = result;
        if (!destination) {
            return;
        }

        const fromColumnIndex = Number(source.droppableId);
        const fromIssueIndex = source.index;
        const toColumnIndex = Number(destination.droppableId);
        const toIssueIndex = destination.index;

        if (fromColumnIndex === toColumnIndex && fromIssueIndex === toIssueIndex) {
            return
        }

        const {list} = this.state;
        const oldData = cloneDeep(list); // 上一个数据备份

        const TempIssue = list[fromColumnIndex].issues[fromIssueIndex]; // 当前拖拽的值


        let TempData = update(cloneDeep(list), {
            [fromColumnIndex]: {
                issues: issues =>
                    update(cloneDeep(issues), {
                        $splice: [[fromIssueIndex, 1]],
                    }),
            },
        });

        TempData = update(cloneDeep(TempData), {
            [toColumnIndex]: {
                issues: issues =>
                    update(issues, {
                        $splice: [[toIssueIndex, 0, TempIssue]],
                    }),
            },
        });
        this.setState({
            list: TempData,
            activeColumn: null,
            activeIssues: null,
        }, () => {
            if (fromColumnIndex !== toColumnIndex) {
                // console.log('切换栏');
                let toColumnData = list && list[toColumnIndex] || {};
                if (isEmpty(toColumnData)) {
                    return;
                }
                const $this = this.props.qtins || {};
                const _this = this;
                let appCode = $this.getAppCode();
                let ajaxData = {
                    dataId: TempIssue.id,
                    stateId: toColumnData.id,
                    appCode
                };
                if ($this.request) {
                    this.setState({loading: true});
                    $this.request(changeKanbanStateApi, ajaxData).then(rsp => {
                        if (rsp && 200 == rsp.status) {

                        } else {
                            _this.setState({list: oldData});
                        }
                    }).catch(() => {
                        _this.setState({list: oldData});
                    }).finally(() => {
                        _this.setState({loading: false});
                    })
                }
                // console.log('ajaxData', ajaxData);
            }
        })
    }

    /**
     * 加载更多数据
     * @param state
     */
    loadMore(state) {
        const $this = this.props.qtins;

        let fAppCode = $this.getAppCode();
        let listFunc = $this.getFromPropAppins('fetchList');
        if (!isFunction(listFunc)) {
            listFunc = $this.fetchListFunc.bind(this);
        }

        if (fAppCode && isFunction(listFunc)) {
            let ajaxData = $this.getAjaxData4List();
            ajaxData.maxResults = 20;
            ajaxData.startIndex = this.getListStartIndex(state);
            ajaxData.filterIns.andEqual('state.id', state);
            ajaxData.filter = ajaxData.filterIns.toJson();

            // console.log('ajaxData', ajaxData);
            this.setState({loading: true});
            const fetchPromise = listFunc(ajaxData, {}, this);

            if (fetchPromise instanceof Promise) {
                fetchPromise.then((rsp) => {
                    if (rsp && rsp.status === 200) {
                        let rspData = rsp.data || {};
                        let list = isArray(rspData) ? rspData : (rspData.results || rspData.records);

                        if (!isEmpty(list)) {
                            this.updatePushListFn(state, list);
                        }

                    }
                }).finally(() => {
                    this.setState({loading: false});
                })
            } else {
                this.setState({loading: false});
            }
        }
    }

    /**
     * 在点击每一个状态下加载更多的数据时，获取从第几条继续加载数据
     * @param state
     * @returns {number}
     */
    getListStartIndex(state) {
        const {list} = this.state;
        let index = 0;
        if (!isEmpty(list)) {
            map(list, item => {
                if (item.id == state && !isEmpty(item.issues)) {
                    index = item.issues.length;
                }
                return item;
            })
        }

        return index;
    }

    render() {
        const {style, appins} = this.props;
        const {list, activeColumn, activeIssues, loading, colsConf} = this.state;
        // console.log('list', list);
        return (

            <div style={{
                ...style,
                width: '100%',
                minHeight: '300px',
                backgroundColor: '#ffffff',
                position: 'relative'
            }}>
                {loading && <div className={styles.maskingModel}>
                    <div className={styles.maskingModelContent}>
                        <Spin/>
                    </div>
                </div>}
                {
                    !isEmpty(list) && <DragDropContext onDragEnd={this.onDragEnd.bind(this)}
                                                       onDragStart={this.onDragStart.bind(this)}>
                        <div className={styles.container} >
                            {!isEmpty(list) && list.map((column, index) => {
                                return (
                                    <Column
                                        colsConf={colsConf}
                                        appins={appins}
                                        columnIndex={index}
                                        key={column.id}
                                        activeColumn={activeColumn}
                                        activeIssues={activeIssues}
                                        column={column}
                                        loadMore={this.loadMore.bind(this)}
                                    />
                                );
                            }) || ''}
                        </div>
                    </DragDropContext>
                }
            </div>
        );
    }
}

